package org.chen.boot.web;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;
import org.chen.mvc.protocol.DispatcherServlet;
import org.chen.spring.core.annotation.Autowired;
import org.chen.spring.core.annotation.Component;


import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

/**
 * @author Chen
 * @since 2023/6/7 14:17
 */

@Component
public class TomcatWebServer implements WebServer {

    @Autowired
    private ServerConfig serverConfig;

    @Override
    public void start() {
        startTomcat(serverConfig.getPort());
    }

    public static void startTomcat(Integer port) {
        try {
            checkPort(port);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        //自研的Tomcat
        org.chen.tomcat.Tomcat tomcat1 = new org.chen.tomcat.Tomcat();
        tomcat1.setPort(port);
        tomcat1.setDispatcherServlet(new DispatcherServlet());
        try {
            tomcat1.start();
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    tomcat1.stop();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 旧的启动方式 （保留一下代码）
     */
    @Deprecated
    public static void oldStart(Integer port) {
        Tomcat tomcat = new Tomcat();
        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");
        Connector connector = new Connector();
        connector.setPort(port);
        StandardEngine standardEngine = new StandardEngine();
        standardEngine.setDefaultHost("localhost");
        StandardHost standardHost = new StandardHost();
        standardHost.setName("localhost");

        String contextPath = "";
        StandardContext standardContext = new StandardContext();
        standardContext.setPath(contextPath);
        standardContext.addLifecycleListener(new Tomcat.FixContextListener());

        standardHost.addChild(standardContext);
        standardEngine.addChild(standardHost);

        service.setContainer(standardEngine);
        service.addConnector(connector);

        tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet());
        standardContext.addServletMappingDecoded("/*", "dispatcher");
        try {
            tomcat.start();
            Server server1 = tomcat.getServer();
            server1.await();
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    tomcat.stop();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }));
        } catch (LifecycleException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据输入端口号检查端口是否被占用
     *
     * @param port 端口号
     */
    public static void checkPort(int port) throws IOException {
        boolean flag = false;
        InetAddress theAddress = InetAddress.getByName("127.0.0.1");
        try (Socket ignored = new Socket(theAddress, port)) {
            flag = true;
        } catch (IOException e) {
            //如果测试端口号没有被占用，那么会抛出异常，通过下文flag来返回可用端口
        }
        //new了socket最好释放
        if (flag) {
            throw new IOException("端口：" + port + "被占用");
        }
    }
}
